home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
330_03
/
tskstck.asm
< prev
next >
Wrap
Assembly Source File
|
1990-10-10
|
9KB
|
424 lines
;
; --- Version 2.2 90-10-12 15:33 ---
;
; CTask - Local Stack Switch handler module.
;
; Public Domain Software written by
; Thomas Wagner
; Ferrari electronic Gmbh
; Beusselstrasse 27
; D-1000 Berlin 21
; Germany
;
; This file is new with version 1.2.
;
; In this version, all Hard- and Software INT handlers switch
; to a local stack (INT 16 for AH=0 only). Stack overruns have
; been observed, especially in conjunction with VDISK and the
; Microsoft Editor. Some Microsoft products (and some other TSR's)
; link into interrupts without switching to local stacks. This
; can lead to situations where just a few words are available
; for use by the CTask handlers. In the abovementioned combination,
; a keyboard interrupt occurring while VDISK is active leaves
; four (!) words of stack space for INT 16 execution.
; Since most of the interrupts should be reentrant, a number
; of stacks are maintained (constant NUM_STACKS), and the call
; is passed without a stack switch if all local stacks are in use.
;
; To avoid duplication of the stack switch and register save code
; in all handlers, a global stack switcher is implemented here.
; It pushes the address of a back-switch routine on the new stack,
; so the calling routine doesn't have to care about explicitly
; calling the restore routine.
;
; No registers may be pushed prior to the call to switch_stack if
; the auto-switchback is to be used, since switch_stack assumes
; the old stack to contain the callers flags at offset 4.
;
; When old_stack is called to explicitly switch back, stack
; contents prior to the call to switch_stack are insignificant.
;
; Switch_stack will set up registers as follows:
; BP = base of register save area on stack
; DS,ES = DGROUP
; Direction flag clear
; Interrupts enabled
; All other registers are unchanged.
;
; To allow preservation of the flag state on entry to switch_stack,
; the flags are pushed on the save area, but not automatically
; restored. Copy the entry_flags into caller_flags to restore
; the entry flags on return.
;
; old_stack will not restore flags from the stack, it will preserve
; the flag state.
;
; Version 2.1 slightly changes the handling of flag restoration
; on auto-backswitch. The old algorithm restored the caller flags
; on entry to the backswitch routine, which caused problems with
; debuggers if the interrupted code was being single-stepped.
; Now the original flags always will be restored on exit of the
; back-switch, regardless of the return used (IRET or RET 2).
; To modify the flags returned, you have to explicitly modify
; the caller_flags field in the saved register area.
;
name tskstck
;
include tsk.mac
include tskdeb.h
;
.tsk_model
;
Pubfunc tsk_switch_stack
Pubfunc tsk_old_stack
;
IF DEBUG AND DEB_FLASHERS
Locext tsk_inccdis
extrn tsk_debflash: word
extrn tsk_dtposn: dword
ENDIF
;
;
STACKSIZE = 256 ; local stack size (bytes)
NUM_STACKS = 8 ; Number of local stacks
;
IF FAR_STACKS
ctask_stacks segment word public 'CTASK_STACKS'
ELSE
.tsk_data
ENDIF
;
lstacks label word
db NUM_STACKS * STACKSIZE dup (?)
;
IF FAR_STACKS
ctask_stacks ends
.tsk_data
ENDIF
;
IF NOT ROM_CODE
;
.tsk_edata
.tsk_code
;
sseg equ <cs>
ENDIF
;
stack_full dw 0 ; count 'all stacks in use' events
IF DEBUG AND DEB_FLASHERS
usecnt db 0
ENDIF
EVEN
;
;
IF ROM_CODE
r_ds dw ?
ENDIF
r_ss dw ?
r_sp dw ?
r_bx dw ?
r_cx dw ?
r_bp dw ?
call_ip dw ?
call_cs dw ?
retaoff dw ?
IF LOCALS_FAR
retaseg dw ?
ENDIF
sflags dw ?
;
; Caution: Since a zero slot offset is used to detect
; that no stack was allocated, the "stacks" array may not
; be located at offset 0 in the segment.
;
stacks label word
xst = offset lstacks + STACKSIZE
rept NUM_STACKS
dw xst
xst = xst + STACKSIZE
endm
;
IF ROM_CODE
;
.tsk_edata
.tsk_code
;
sseg equ <ds>
ENDIF
;
tsk_dgroup dw @CTASK_DATA
;
IF FAR_STACKS
stackseg dw SEG ctask_stacks
ELSE
stackseg equ <tsk_dgroup>
ENDIF
;
;
Localfunc tsk_switch_stack
;
IF ROM_CODE
push ds
mov ds,cs:tsk_dgroup
pop r_ds
ENDIF
pushf
cli
pop sseg:sflags
pop sseg:retaoff ; return address
IF LOCALS_FAR
pop sseg:retaseg
ENDIF
mov sseg:r_bx,bx ; save bx & cx in CS
mov sseg:r_cx,cx
mov sseg:r_bp,bp ; save BP
mov bp,sp
mov bx,[bp] ; get caller's IP
mov sseg:call_ip,bx
mov bx,2[bp] ; get caller's CS
mov sseg:call_cs,bx
mov bp,4[bp] ; get caller's flags into BP
;
mov cx,NUM_STACKS ; total number of stacks
mov bx,offset stacks ; stack table
stlp:
cmp word ptr sseg:[bx],0 ; in use ?
jne st_found ; jump if free
inc bx
inc bx
loop stlp
;
; No unused stack, continue on caller's stack
;
IF DEBUG AND DEB_FLASHERS
push ds
mov ds,cs:tsk_dgroup
cmp tsk_debflash,0
je debdd0
push ax
mov ax,DEBP_CNTSTOFL
call tsk_inccdis
pop ax
debdd0:
pop ds
ENDIF
inc sseg:stack_full
xor bx,bx
jmp short st_old
;
; Stack found, perform switch
;
st_found:
mov sseg:r_ss,ss ; save SS/SP
mov sseg:r_sp,sp
mov ss,cs:stackseg ; load new SS/SP
mov sp,sseg:[bx]
mov cx,sp ; save new SP value
mov word ptr sseg:[bx],0 ; mark stack in use
push sseg:r_ss ; push old SS/SP
push sseg:r_sp
st_old:
push sseg:r_bx
push sseg:r_cx
push bx ; push stack slot index
push cx ; push new SP
;
push ax ; push remaining regs
push dx
push si
push di
push sseg:r_bp
IF ROM_CODE
push r_ds
ELSE
push ds
ENDIF
push es
;
push bp ; push caller's flags
push sseg:call_cs ; push caller's CS
push sseg:call_ip ; push caller's IP
;
push sseg:sflags ; push entry flags
push cs ; and special return
mov cx,offset @stsw_retn
push cx
mov bx,sseg:r_bx ; restore regs bx,cx
mov cx,sseg:r_cx
mov bp,sp ; set BP to stack bottom
IF LOCALS_FAR
push sseg:retaseg
ENDIF
push sseg:retaoff ; push retaddr on new stack
cld
sti
mov ds,cs:tsk_dgroup
mov es,cs:tsk_dgroup
IF DEBUG AND DEB_FLASHERS
cmp slot_idx[bp],0
je debdd1
cmp tsk_debflash,0
je debdd1
inc sseg:usecnt
push ax
push ds
push si
mov al,sseg:usecnt
add al,'0'
lds si,tsk_dtposn
mov DEBP_STACKNUM[si],al
pop si
pop ds
pop ax
debdd1:
ENDIF
ret ; restore flags & return
;
tsk_switch_stack endp
;
;
Localfunc tsk_old_stack
;
pushf ; save flags
cli
IF ROM_CODE
mov ds,cs:tsk_dgroup
ENDIF
pop sseg:sflags
pop sseg:retaoff ; return address
IF LOCALS_FAR
pop sseg:retaseg
ENDIF
add sp,12 ; discard dummy return & flags
;
IF DEBUG AND DEB_FLASHERS
mov ds,cs:tsk_dgroup
cmp slot_idx[bp],0
je debdd2
cmp tsk_debflash,0
je debdd2
dec sseg:usecnt
mov al,sseg:usecnt
add al,'0'
lds si,tsk_dtposn
mov DEBP_STACKNUM[si],al
IF ROM_CODE
mov ds,cs:tsk_dgroup
ENDIF
debdd2:
ENDIF
;
pop es ; restore regs
IF ROM_CODE
pop r_ds
ELSE
pop ds
ENDIF
pop bp
pop di
pop si
pop dx
pop ax
;
pop cx ; new SP
pop bx ; stack slot index
or bx,bx ; no new stack?
jnz old_sw
pop cx
pop bx
jmp short old_ret
old_sw:
mov sseg:[bx],cx ; reset stack slot
pop cx
pop bx
pop sseg:r_sp
pop ss ; old SS
mov sp,sseg:r_sp
old_ret:
IF LOCALS_FAR
push sseg:retaseg
ENDIF
push sseg:retaoff ; push retaddr on old stack
push sseg:sflags
IF ROM_CODE
mov ds,r_ds
ENDIF
popf ; restore flags
ret ; and return
;
tsk_old_stack endp
;
; stsw_retn is where the call returns to when there is no explicit
; call to old_stack.
;
@stsw_retn proc far
;
cli
add sp,4 ; discard caller CS/IP
IF ROM_CODE
mov ds,cs:tsk_dgroup
ENDIF
pop sseg:sflags ; store caller's flags in CS
;
IF DEBUG AND DEB_FLASHERS
mov ds,cs:tsk_dgroup
cmp slot_idx[bp],0
je debdd3
cmp tsk_debflash,0
je debdd3
dec sseg:usecnt
mov al,sseg:usecnt
add al,'0'
lds si,tsk_dtposn
mov DEBP_STACKNUM[si],al
IF ROM_CODE
mov ds,cs:tsk_dgroup
ENDIF
debdd3:
ENDIF
;
pop es ; restore regs
IF ROM_CODE
pop r_ds
ELSE
pop ds
ENDIF
pop bp
pop di
pop si
pop dx
pop a